/**
 * https://github.com/appstract/vue-validate/blob/master/src/v-validate.js
 * https://github.com/angular/angular/blob/master/packages/forms/src/validators.ts
 */

function isEmptyInputValue(value) {

  return value == null || value.length === 0;
}

const regList = {
  EMAIL_REGEXP: /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/,
}

export class Validators {

}


Validators.min = (min) => {
  return (control) => {
    if (isEmptyInputValue(control.value) || isEmptyInputValue(min)) {
      return null;
    }
    const value = parseFloat(control.value);
    return !isNaN(value) && value < min ? {'min': {'min': min, 'actual': control.value}} : null;
  };
}

Validators.max = (max) => {
  return (control) => {
    if (isEmptyInputValue(control.value) || isEmptyInputValue(max)) {
      return null;
    }
    const value = parseFloat(control.value);
    return !isNaN(value) && value > max ? {'max': {'max': max, 'actual': control.value}} : null;
  };
}

Validators.required = (control) => {
  return isEmptyInputValue(control.value) ? {'required': true} : null;
}

Validators.requiredTrue = (control) => {
  return control.value === true ? null : {'required': true};
}

Validators.email = (control) => {
  return regList.EMAIL_REGEXP.test(control.value) ? null : {'email': true};
}

Validators.minLength = (minLength) => {
  return (control) => {
    if (isEmptyInputValue(control.value)) {
      return null;
    }
    const length: number = control.value ? control.value.length : 0;
    return length < minLength ?
        {'minlength': {'requiredLength': minLength, 'actualLength': length}} :
        null;
  };
}

Validators.maxLength = (maxLength) => {
  return (control) => {
    const length: number = control.value ? control.value.length : 0;
    return length > maxLength ?
        {'maxlength': {'requiredLength': maxLength, 'actualLength': length}} :
        null;
  };
}

Validators.pattern = (pattern) => {
  if (!pattern) return Validators.nullValidator;
  let regex;
  let regexStr;
  if (typeof pattern === 'string') {
    regexStr = '';

    if (pattern.charAt(0) !== '^') regexStr += '^';

    regexStr += pattern;

    if (pattern.charAt(pattern.length - 1) !== '$') regexStr += '$';

    regex = new RegExp(regexStr);
  } else {
    regexStr = pattern.toString();
    regex = pattern;
  }
  return (control) => {
    if (isEmptyInputValue(control.value)) {
      return null;
    }
    const value: string = control.value;
    return regex.test(value) ? null :
                                {'pattern': {'requiredPattern': regexStr, 'actualValue': value}};
  };
}

Validators.nullValidator = () => {
  return null;
}

Validators.compose = (validators) => {
  if (!validators) return null;
  const presentValidators = validators.filter(isPresent);
  if (presentValidators.length == 0) return null;

  return function(control) {
    return _mergeErrors(_executeValidators(control, presentValidators));
  };
}

Validators.composeAsync = (validators) => {
  if (!validators) return null;

  const presentValidators = validators.filter(isPresent);
  if (presentValidators.length == 0) return null;

  return function(control) {

    return Promise.all(_executeValidators(control, presentValidators));
  };
}


function isPresent(o) {
  return o != null;
}

// 执行每个方法里返回值得集合
function _executeValidators(control, validators){
  return validators.map(v => v(control));
}

function _executeAsyncValidators(control, validators) {
  return validators.map(v => v(control));
}

function _mergeErrors(arrayOfErrors) {
  const res: {[key: string]: any} =
      arrayOfErrors.reduce((res, errors) => {
        return errors != null ? {...res, ...errors} : res;
      }, {});
  return Object.keys(res).length === 0 ? null : res;
}


